package com.qf.shiro;

import com.qf.pojo.DtsAdmin;
import com.qf.service.AdminService;
import com.qf.service.PermissionService;
import com.qf.service.RoleService;
import com.qf.util.bcrypt.BCryptPasswordEncoder;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Set;

/**
 * 自定义Realm用来对用户名密码进行校验，和登录后授权
 * @author fy
 * @version V1.0
 * @Project workspace
 * @Package com.qf.shiro
 * @Description:
 * @Date 2022/6/20 17:49
 */
public class AdminAuthorizingRealm extends AuthorizingRealm {
    @Autowired
    private AdminService adminService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;

    /**
     * 用户登录成功后，对用户进行授权，授予用户对应的角色和权限
     * @param principal
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principal) {
        //1.获取认证后的当前用户对象
        DtsAdmin admin = (DtsAdmin)getAvailablePrincipal(principal);
        //2.根据用户对象获取角色ids
        Integer[] roleIds = admin.getRoleIds();
        //3.根据角色id集合到数据库中查找对应的角色名集合
        Set<String> roleSet = roleService.queryByIds(roleIds);

        //4.根据角色id集合，到数据库中查询对应的权限字符串集合
        Set<String> permSet = permissionService.queryPermissionByRoleIds(roleIds);


        //5.将角色名称集合，和权限字符春集合交给shiro框架
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

        //6.返回封装后的shiro权限对象
        info.setRoles(roleSet);
        info.setStringPermissions(permSet);

        return info;
    }

    /**
     * 接受页面传入的用户名密码，根据数据库的用户名密码进行校验
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1.获取用户页面中输入的用户名，密码
        UsernamePasswordToken UsernameAndPwd = (UsernamePasswordToken)token;
        String username = UsernameAndPwd.getUsername();
        String password = new String(UsernameAndPwd.getPassword());
        //2.判断如果用户名为空，返回异常提示信息
        if (StringUtils.isEmpty(username)){
            throw new AccountException("用户名为空");
        }
        //3.判断如果密码为空，返回异常提示信息
        if (StringUtils.isEmpty(password)){
            throw new AccountException("密码错误");
        }

        //4.根据用户名，获取用户对象集合
        List<DtsAdmin> list = adminService.findAdminByUsername(username);

        //5.判断如果获取不到用户对象，返回异常提示信息
        if (list==null||list.size()==0){
            throw new UnknownAccountException("用户名错误");
        }
        //6.如果用户对象大于1哥，那么说明存在同名账户，不允许登录
        if (list.size()>=2){
            throw new UnknownAccountException("存在同名账户，请联系管理员修改");
        }

        DtsAdmin dtsAdmin = list.get(0);//获取唯一对象

        //7.判断如果密码不正确返回异常提示信息
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        //密码使用BCrypt算法进行加密
        //encoder.matches(参数1，参数2)，第一哥参数是明文密码，第二个参数是从数据库中获取的加密后密码
        //两者进行匹配，返回校验结果
        if (!encoder.matches(password, dtsAdmin.getPassword())){
            throw new UnknownAccountException("密码错误！");
        }
        //8.封装shiro指定的对象交给shiro框架
        SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(dtsAdmin, password, this.getName());

        return info;
    }
}
